/**
 * const 不允许修改引用地址
 *
 * 尽量不要使用var 主要使用const 配合使用let
 */

/**
 * 解构
 */

// 数组

// const arr = [100, 200, 300]

// const [a, b, c] = arr
// console.log(a,b,c);

// const [, , c] = arr
// console.log(c);

// const [a, ...rest] = arr
// console.log(a, rest);

// const [a, b, c = 1, more = 123] = arr
// console.log(c, more);

// 对象
// const obj = { name: "wlz", age: 18 };

// const name = "xxz";
// const { name: name1 = "jack" } = obj;
// // console.log(name1);
// const { log } = console;
// console.log(name1);

/**
 * 字符串模版
 */
// const message = 'Error: foo is not defined'

// console.log(
//     message.startsWith('Error'),
//     message.endsWith('defined'),
//     message.includes('foo')
// );

/**
 * 参数默认值 剩余参数
 */

//  function foo (a,b = 1) {
//     console.log(b);
//  }

//  foo()

// function foo (a, ...args) {
//     console.log(args);
// }

// foo(1,2,3,4,5,6)

/**
 * 扩展运算符Fira Code Light
 */
// const arr = [1, 2, 34, 45];
// console.log.apply(console, arr);

// console.log(...arr);

/**
 * 箭头函数
 * this指向调用的对象
 */
// const arr = [1, 2, 34, 45];
// arr1 = arr.map(i => i * 2);
// console.log(arr1);

/**
 * 计算属性名
 */

// let obj = {
//     a: 1,
//     b: 2,
//     [1 + 2]: 3,
// };

// console.log(obj);

/**
 * Object.assign
 * Object.is
 */

// const o = {
//     a: 123,
//     b: 234
// }

// const t = {
//     a: 111,
//     c: 333
// }

// const r = Object.assign(t, o)
// console.log(t);
// console.log(t === r);

// console.log(
//     0 == false,
//     0 === false,
//     +0 === -0,
//     Object.is(+0, -0),
//     NaN === NaN,
//     Object.is(NaN, NaN)
// );

/**
 * Proxy
 * 对象访问代理器
 */
// const person = {
//     name: 'wlz',
//     age: 18
// }

// const personProxy = new Proxy(person, {
//     get(target, prop) {
//         return prop in target ? target[prop] : 'default'
//     },
//     set(target, prop, val) {
//         target[prop] = val
//     }
// })

// personProxy.age = 100

// personProxy.sex = 'man'

// console.log(personProxy.age);
// console.log(personProxy.sex);
// console.log(personProxy.a);

/**
 * Proxy vs Object.defineProperty
 */

// const person = {
//     name: "wlz",
//     age: 18,
// };

// const personProxy = new Proxy(person, {
//     deleteProperty(target, property) {
//         console.log('delete', property);
//         delete target[property]
//     }
// });

// delete personProxy.age

/**
 * Reflect
 * Reflect并非一个构造函数，所以不能通过new运算符对其进行调用，或者将Reflect对象作为一个函数来调用。Reflect的所有属性和方法都是静态的
 * Reflect与proxy handlers的方法相同
 */
// const person = {
//     name: "wlz",
//     age: 18,
// };

// const personProxy = new Proxy(person, {
//     deleteProperty(target, property) {
//         console.log("delete", property);
//         return Reflect.deleteProperty(target, property)
//     },
// });

// delete personProxy.age;
// console.log(personProxy);

// console.log(Reflect.has(person, 'name'));
// console.log(Reflect.deleteProperty(person, 'age'));
// console.log(Reflect.ownKeys(person));

/**
 * class
 *   -> static 静态方法
 *   -> extends 继承
 *      -> super 始终指向父类
 */

// function Preson(name){
//     this.name = name
// }
// Preson.prototype.say = function() {
//     console.log(this.name);
// }

// class Preson {
//     constructor(name) {
//         this.name = name;
//     }
//     say() {
//         console.log(this.name);
//     }
//     static hello() {
//         console.log("hello");
//     }
// }
// let p = new Preson('wlz')
// p.say()
// Preson.hello()

// class student extends Preson {
//     constructor(name, number) {
//         super(name);
//         this.number = number;
//     }
//     word() {
//         super.say();
//         console.log(this.name, this.number);
//     }
// }
// let s = new student("wlz", 13);
// s.word();

/**
 * Set（集合）
 * 类似数组，无重复值
 * Set本身是一个构造函数，用来生成Set数据结构，Set 函数可以接受一个数组（或者具有 iterable 接口的其他数据结构，比如类数组--节点集合）作为参数，用来初始化
 */
//  const s = new Set()
//  s.add(1).add(2).add(3).add(4)
//  console.log(s);
//  s.forEach(i => console.log(i))
//  for(let i of s) {
//      console.log(i);
//  }

/**
 * Map（字典）
 * 字典数据结构
 * 字典结构——用来存储不重复key的hash结构。不同于集合（set）的是，字典使用的是键值对的形式来存储数据
 * 各种类型的值都可以当做key
 */
// obj = {
//     true: 1,
//     123: 2,
//     [{ a: 1 }]: 3,
// };
// // 普通对象只能使用字符串作为Key
// console.log(Object.keys(obj));
// console.log(obj["[object Object]"]);

// const m = new Map();

// const tom = { name: "tom" };
// m.set(tom, 90);
// console.log(m);
// console.log(m.get(tom));
// m.set({ name: "wlz" }, 100);
// console.log(m);
// console.log(m.get({name: 'wlz'})); // 引用地址不同 输出undefined

/**
 * Symbol 表示独一无二的值
 */

// const s = Symbol();
// console.log(typeof s);

// console.log(Symbol() === Symbol());

//从es2015开始 Object可以使用Symbol类型作为key

// const name = Symbol();

// let obj = {
//     [name]: "wlz",
// };
// console.log(obj[name]);
// console.log(obj[Symbol()]);

// console.log(Symbol.for("true") === Symbol.for(true)); // 参数不是字符串时 自动转换为字符串

/**
 * for...of
 * 将作为之后的标准循环方法
 * 实现了 iterable接口 的数据类型
 */

// const arr = [100, 200, 300, 400];

// for (const item of arr) {
//     console.log(item);
//     break
// }
// const m = new Map()
// m.set('a', '123')
// m.set('b', '324')

// for (const [key, value] of m) {
//     console.log(key, value);
// }

// const obj = {
//     a: 123,
//     b: 234,
//     c: 345
// }

// // obj is not iterable
// for (const item of obj) {
//     console.log(item);
// }

/**
 * iterable接口
 */

// iterator （迭代器）
// const arr = [100, 200, 300, 400];
// let iterator =  arr[Symbol.iterator]()
// iterator.next() // {value: 100, done: false}
// iterator.next() // {value: 200, done: false}
// iterator.next() // {value: 300, done: false}
// iterator.next() // {value: 400, done: false}
// iterator.next() // {value: undefined, done: true}

/**
 * 实现可迭代接口
 */
// const obj = {
//     a: 123,
//     b: 234,
//     c: 345,
//     [Symbol.iterator]: function() {
//         const self = this
//         let index = 0
//         return {
//             next: function() {
//                 return {
//                     value: [Object.keys(self)[index], self[Object.keys(self)[index]]],
//                     done: index++ >= Object.keys(self).length
//                 }
//             }
//         }
//     }
// }

// for (const [key, value] of obj) {
//     console.log(key, value);
// }

/**
 * Generator
 */
function* foo() {
    console.log("11111");
    yield 100;
    console.log("22222");
    yield 200;
    console.log("33333");
    yield 300;
}

const result = foo();
// console.log(result); // Object [Generator] {}  返回的是Generator对象
// 惰性执行
// console.log(result.next()); // { value: 100, done: false }
// console.log(result.next()); // { value: 200, done: false }
// console.log(result.next()); // { value: 300, done: false }
// console.log(result.next()); // { value: undefined, done: true }

// 使用Generator来实现iterable接口
// const obj = {
//     a: 123,
//     b: 234,
//     c: 345,
//     [Symbol.iterator]: function * () {
//         const all = Object.keys(this)
//         for (const item of all) {
//             yield [item, this[item]]
//         }
//     }
// }

// for (const [key, value] of obj) {
//     console.log(key, value);
// }

/**
 * es2016
 *
 * includes
 * 指数运算符(次方)  (2 ** 3) -> 8
 */

/**
 * es2017
 *
 * Object.values() 返回对象中所有的值
 * Object.entrise() 以数组的形式返回所有的键值对
 * Object.getOwnPropertyDescriptor() 返回指定对象上一个自有属性对应的属性描述符
 *
 * String
 *
 * padStart() '1'.padStart(2, 0) -> 01
 * padEnd()   '1'.padStart(2, 0) -> 10
 * 
 * Async/Await
 */
